package com.sky.agent.service.impl;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson2.JSONObject;
import com.eatthepath.pushy.apns.ApnsClient;
import com.eatthepath.pushy.apns.ApnsClientBuilder;
import com.eatthepath.pushy.apns.PushNotificationResponse;
import com.eatthepath.pushy.apns.auth.ApnsSigningKey;
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
import com.sky.agent.utils.AESUtil;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Slf4j
@Service
public class IosPushMsgService {

    @Value("${message.ios.bundleId:44dc656cee655748236621c939da16670bc4c7b7a36db1b39023efa3716696c2}")
    private String bundleId;

    @Value("${message.ios.teamId:336b8ba3768ffaa2c67f88a876fc5108d5b78787058002780c1881477e1be5b8}")
    private String teamId;

    @Value("${message.ios.apnKeyId:1b11fbc5f08b74504ed193de57afc18ce3ec19ba4c1f624aeed6bf3b165aee75}")
    private String apnKeyId;


    private ApnsClient apnsClient;


    public void init(String apnKeyPath, String iosMessagePushUrl) throws Exception {
        // 初始化 APNs 客户端
        final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        // 加载 APNs 密钥
        final ApnsSigningKey signingKey = ApnsSigningKey.loadFromInputStream(
                new FileInputStream(apnKeyPath),
                Base64.decodeStr(AESUtil.decrypt(teamId)),  // team ID
                Base64.decodeStr(AESUtil.decrypt(apnKeyId))   // key ID
        );

        // 构建 APNs 客户端
        final ApnsClientBuilder apnsClientBuilder = new ApnsClientBuilder();
        apnsClientBuilder.setApnsServer(iosMessagePushUrl);

        apnsClientBuilder.setSigningKey(signingKey);
        apnsClientBuilder.setEventLoopGroup(eventLoopGroup);

        // 添加连接超时设置
        apnsClientBuilder.setConnectionTimeout(Duration.ofSeconds(10));

        this.apnsClient = apnsClientBuilder.build();
    }

    /**
     * 发送推送通知到指定 iOS 设备
     *
     * @param deviceToken 设备令牌（从客户端获取并存储）
     * @param title       通知标题
     * @param body        通知内容
     * @return 推送结果
     */
    public String sendPushNotification(String deviceToken, String title, String body) throws Exception {
        // 1. 清洗设备令牌，移除所有非十六进制字符
        String cleanedToken = cleanDeviceToken(deviceToken);
        log.info("使用清洗后的设备令牌: {}", cleanedToken);

        // 2. 构建符合APNs规范的通知payload
        JSONObject alert = new JSONObject();
        alert.put("title", title);
        alert.put("body", body);

        JSONObject aps = new JSONObject();
        aps.put("alert", alert);
        aps.put("sound", "default");  // 通知声音
        aps.put("badge", 1);          // 应用图标角标数字
//            // 增加内容可用字段，确保在后台也能收到
//            aps.put("content-available", 1);

        JSONObject payload = new JSONObject();
        payload.put("aps", aps);

        // 转为JSON字符串
        final String payloadString = payload.toString();
        log.info("推送Payload: {}", payloadString);

        // 检查payload大小，普通通知不能超过4KB
        if (payloadString.getBytes().length > 4096) {
            log.error("推送内容过大，超过4KB限制");
            return "推送内容过大，超过4KB限制";
        }

        // 3. 创建推送通知对象
        final SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(
                cleanedToken,
                Base64.decodeStr(AESUtil.decrypt(bundleId)),  // bundle ID
                payloadString
        );

        // 4. 发送通知并获取结果
        final CompletableFuture<PushNotificationResponse<SimpleApnsPushNotification>> future =
                apnsClient.sendNotification(pushNotification);

        // 等待推送结果，设置超时时间
        final PushNotificationResponse<SimpleApnsPushNotification> response =
                future.get(30, TimeUnit.SECONDS);

        // 5. 处理推送结果
        if (response.isAccepted()) {
            log.info("推送成功！通知ApnsId: {}，Apns push Status: {}", response.getApnsId(), response.getStatusCode());
            return null;
        } else {
            // 详细打印错误信息
            log.error("推送被拒绝: {}，错误代码：{}", response.getRejectionReason(), response.getRejectionReason().get());

            // 处理常见错误
            String failedStr = handleRejectionReason(response.getRejectionReason().get(), cleanedToken);
            return failedStr;
        }
    }

    /**
     * 清洗设备令牌，移除所有非十六进制字符
     */
    private String cleanDeviceToken(String deviceToken) {
        if (deviceToken == null) {
            return "";
        }
        // 移除所有非十六进制字符
        return deviceToken.replaceAll("[^0-9a-fA-F]", "").toLowerCase();
    }

    /**
     * 处理常见的推送拒绝原因
     */
    private String handleRejectionReason(String reason, String deviceToken) {
        String failedStr = "";
        switch (reason) {
            case "BadDeviceToken":
                log.error("无效的设备令牌: {}, 请检查令牌是否正确或已过期", deviceToken);
                // 这里可以添加逻辑，将无效令牌从数据库中移除
                failedStr = "无效的设备令牌: " + deviceToken + ", 请检查令牌是否正确或已过期";
                break;
            case "DeviceTokenNotForTopic":
                log.error("设备令牌与bundle ID不匹配，请检查bundle ID是否正确");
                failedStr = "设备令牌与bundle ID不匹配，请检查bundle ID是否正确";
                break;
            case "ExpiredProviderToken":
                log.error("推送证书已过期，请更新证书");
                failedStr = "推送证书已过期，请更新证书";
                break;
            case "MismatchedCredential":
                log.error("证书与推送服务器环境不匹配，开发证书应使用sandbox服务器");
                failedStr = "证书与推送服务器环境不匹配，开发证书应使用sandbox服务器";
                break;
            case "PayloadTooLarge":
                log.error("推送内容过大，请精简内容");
                failedStr = "推送内容过大，请精简内容";
                break;
            default:
                log.error("推送失败，原因: {}", reason);
                failedStr = "推送失败，原因: " + reason;
        }
        return failedStr;
    }

    /**
     * 关闭APNs客户端，应在服务停止时调用
     */
    public void close() {
        if (apnsClient != null) {
            apnsClient.close().whenComplete((v, e) -> {
                if (e != null) {
                    log.error("APNs 客户端关闭失败: {}", e.getMessage());
                } else {
                    log.info("APNs 客户端关闭成功");
                }
            });
        }
    }

    // 示例：使用服务发送通知
    public static void main(String[] args) {
        try {
            // 根据实际环境选择正确的服务器地址
            String apnsServer = "api.sandbox.push.apple.com"; // 开发环境
            // String apnsServer = "api.push.apple.com"; // 生产环境

            IosPushMsgService service = new IosPushMsgService();

            service.init(
                    "/Users/li.sun/Documents/szsk/AuthKey_F36U2J9D9T.p8",  // 替换为实际的p8密钥路径
                    apnsServer);

            // 设备令牌（实际应用中应从数据库或缓存中获取）
            final String deviceToken = "6ee9aae6cb4866a4fff0d1515cd838b20c1cdc60afc072f6984bc48e54d0d8f8";

            // 发送通知
            String result = service.sendPushNotification(deviceToken, "测试通知-20250818", "这是一条来自 Java 后端的推送通知");
            log.info("推送结果: {}", StringUtils.isBlank(result) ? "推送成功" : result);

            // 服务停止时关闭客户端
            service.close();
        } catch (Exception e) {
            log.error("发送推送通知失败", e);
        }
    }
}
